
#include <pthread.h>
#include <math.h>
#include <time.h>
#include <stdio.h>
#include <thread>
#include <string>
#include <array>
#include <vector>
#include <chrono>
#include "../include/new_queue.h"
#include <gtest/gtest.h>

#define N 1000

std::chrono::system_clock::time_point global_start;
std::chrono::system_clock::time_point global_end;

struct Test_Struct {
    int id;
    int count;
    int buf_len;
    char * buf;
    Test_Struct(){};
    Test_Struct(const Test_Struct & another) {
        id = another.id;
        count = another.count;
        buf_len = another.buf_len;
        buf = new char[buf_len + 1];
        memcpy(buf, another.buf, buf_len);
    }
    ~Test_Struct() {
        delete [] buf;
    }
};

void single_get_thread(lf_queue mq){
	void *unit = malloc(8);
	while(1){
		if(mq != nullptr && lf_queue_len(mq) != 0){
			lf_queue_pop(mq, unit);
			printf("unit addr: %p, unit->content: %d\n", unit, (*(Test_Struct **)unit)->id);
			global_end = std::chrono::system_clock::now();
			std::chrono::duration<double> diff = global_end - global_start;
    		printf("[TIME for MulitThread]: %lf us\n", (double) diff.count() * 1000000 / N);
    		return;
		}
	}

}


TEST(MessageQueueTest, SingleThread){
	Test_Struct * test_structs = new Test_Struct();
	lf_queue mq;
	lf_queue_init(&mq, 0, 8, 10000);
	auto start = std::chrono::system_clock::now();
	for(int i = 0; i < N; i++){
		lf_queue_push(mq, &test_structs);
	}
	auto end = std::chrono::system_clock::now();
    std::chrono::duration<double> diff = end-start;
    printf("[TIME for Put Opreation]: %lf us\n", (double) diff.count() * 1000000 / N);
	int len = lf_queue_len(mq);
	printf("queue len: %d\n", len);
	void *unit = malloc(8);
	auto start1 = std::chrono::system_clock::now();
	for(int i = 0; i < N; i++){
		lf_queue_pop(mq, unit);
	}
	auto end1 = std::chrono::system_clock::now();
    std::chrono::duration<double> diff1 = end1-start1;
    printf("[TIME for Get Opreation]: %lf us\n", (double) diff1.count() * 1000000 / N);    
}

TEST(MessageQueueTest, MultiThread){
	Test_Struct * test_structs = new Test_Struct();
	test_structs->id = 11;
	lf_queue mq;
	lf_queue_init(&mq, 0, 8, 10000);
	std::thread *th = new std::thread(single_get_thread, mq);
	sleep(1);
	global_start = std::chrono::system_clock::now();
	lf_queue_push(mq, &test_structs);
//	sleep(1);
	th->detach();
    delete th;

}


int main(int argc, char * argv[]) {
    testing::InitGoogleTest(&argc, argv);  
//    test_multi_threads(); 
    return RUN_ALL_TESTS();;
}